from __future__ import with_statement

import sys
from urlparse import urlunparse

from dbmigrate.datasource import BaseDataSource
from dbmigrate.quarks import *


class DataSource(BaseDataSource):
    
    scheme = "postgres"
    default_port = 5432
    
    show_database_sql = "SELECT datname FROM pg_database WHERE datname='%(db)s'"
    show_tables_sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '%(schema_table)s'"
    select_applied_revisions_sql =  "SELECT %(schema_revision_col)s FROM %(schema_table)s"
    insert_revision_sql =  "INSERT INTO %(schema_table)s (%(migration_package_col)s, %(schema_revision_col)s) VALUES (%(package)s, %(revision)s)"
    delete_revision_sql = "DELETE FROM %(schema_table)s WHERE %(schema_revision_col)s = %(revision)s"
    initial_migration = [
CreateDatabase(), (
"""CREATE SEQUENCE %(schema_table)s_seq""",
"""DROP SEQUENCE %(schema_table)s_seq"""
    ), (
"""CREATE TABLE %(schema_table)s (
            %(id_col)s INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('%(schema_table)s_seq'), 
            %(migration_package_col)s VARCHAR(128) NOT NULL,
            %(schema_revision_col)s BIGINT NOT NULL
    )
""", 
"""DROP TABLE %(schema_table)s"""
    ),
]
    
    def __init__(self):
        super(DataSource, self).__init__()
        self._engine = None

    def dbi_placeholder(self):
        return '%s'
    
    def read_options(self, options, args):
        self.assert_has_required(options, args)
        for (i, x) in enumerate(['admin_user', 'admin_pw', 'user', 'pw', 'db']):
            self.expansionFromArg(args, x, i, None)
        self.expansionFromArg(args, 'host', 5, 'localhost')
        self.expansionFromArg(args, 'port', 6, self.default_port)

    def assert_has_required(self, options, args):
        if len(args) < 5:
            options.error("Expected the arguments: ADMIN_USER ADMIN_PW USER PW DB [HOST [PORT]]") 

    def read_command(self, cmd):
        for x in ['admin_user', 'admin_pw', 'user', 'pw', 'db']:
            self.expansionFromCommand(cmd, x)
        self.expansionFromCommand(cmd, 'host', 'localhost')
        self.expansionFromCommand(cmd, 'port', self.default_port)
            
    def read_config_file(self, config):
        for x in ['admin_user', 'admin_pw', 'user', 'pw', 'db']:
            self.expansionFromIniOption(config, x)
        self.expansionFromIniOption(config, 'host', 'localhost')
        self.expansionFromIniOption(config, 'port', self.default_port)
        
    def admin_uri(self):
        # Connect to the master database by default
        netloc = '%(admin_user)s:%(admin_pw)s@%(host)s:%(port)s' % self.expansions
        return urlunparse([self.scheme, netloc, 'postgres', None, None, None])

    def app_uri(self):
        netloc = '%(user)s:%(pw)s@%(host)s:%(port)s' % self.expansions
        return urlunparse([self.scheme, netloc, self.expansions['db'], None, None, None])
    
    def migration_uri(self):
        netloc = '%(admin_user)s:%(admin_pw)s@%(host)s:%(port)s' % self.expansions
        return urlunparse([self.scheme, netloc, self.expansions['db'], None, None, None])
    
    def set_up_unit_test(self):
        for x in ['user', 'pw', 'db']:
            self.expansionFromRandomString(x, 8, '_tmp')

    def print_unit_test_information(self):
        msg = "Postgres database, username, and password are '%s', '%s', and '%s'"
        subst = tuple(self.expansions[x] for x in ['db', 'user', 'pw'])
        print >> sys.stderr, msg % subst

    def tear_down_unit_test(self):
        pass

    def create_database(self):
        with self.admin_conn.raw_cursor() as c:
            c.execute(self.create_database_sql % self.expansions)

    def drop_database(self):
        with self.admin_conn.raw_cursor() as c:
            c.execute(self.drop_database_sql % self.expansions)
        
